/**
 * 利用fork实现多进程服务器回显；用sigaction实现对子进程的回收；
 * @author: sundx
 * @date: 2020-05-30 17:07:14
 * @Last Modified by: sundx
 * @Last Modified time: 2020-05-31 22:44:28
 */
#include "wrap.h"
#include <csignal>
#include <iostream>
#include <sys/wait.h>

void waitChild(int sig);

int main() {
  int listenFd = sdx::serverSocketBindListen();
  struct sockaddr_in clientAddr;
  socklen_t clientAddrLen = sizeof(clientAddr);
  pid_t pid;
  int mesFd;
  while (1) {

    mesFd = sdx::Accept(listenFd, (sockaddr *)&clientAddr, &clientAddrLen);
    pid = fork();
    if (pid > 0) { // 父进程  监听并回收子进程；
      struct sigaction act;
      struct sigaction oldAct;
      act.sa_flags = 0;
      int ret = sigemptyset(&act.sa_mask);
      if (ret != 0) {
        sdx::printError("sigemptyset error");
      }
      act.sa_handler = waitChild;
      ret = sigaction(SIGCHLD, &act, &oldAct);
      if (ret != 0) {
        sdx::printError("sigaction error");
      }
      close(mesFd);
      continue;
    } else if (pid == 0) { // 子进程
      close(listenFd);
      break;
    } else {
      sdx::printError("fork failed");
    }
  }
  if (pid == 0) { // 子进程工作；
    char inbuff[MESSAGE_SIZE];
    bzero(inbuff, MESSAGE_SIZE); //初始化缓冲区
    char temp[INET_ADDRSTRLEN];
    while (1) {
      int recvBytes = recv(mesFd, inbuff, MESSAGE_SIZE, 0);
      std::cout << "receive " << recvBytes << " bytes message from "
                << inet_ntop(AF_INET, &clientAddr.sin_addr, temp,
                             INET_ADDRSTRLEN)
                << " and the port is " << ntohs(clientAddr.sin_port)
                << ", and the message is " << inbuff << std::endl;
      if (recvBytes == 0) {
        std::cout << "client close the fd..." << std::endl;
        close(mesFd);
        exit(EXIT_SUCCESS);
      }
      send(mesFd, (void *)inbuff, recvBytes, 0);
    }
  }
  return 0;
}

void waitChild(int sig) {
  while (waitpid(0, NULL, WNOHANG) > 0)
    ;
}
